//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_idea_api_serv

import (
	"context"
	"math"
	"time"

	"atomgit.com/openlinksaas/api-server/api_common"
	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/idea_dao"
	"atomgit.com/openlinksaas/api-server/dao/project_dao"
	"atomgit.com/openlinksaas/api-server/dao/user_dao"
	"atomgit.com/openlinksaas/api-server/utils"
	"atomgit.com/openlinksaas/proto-gen-go.git/notices/notices_idea"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_idea_api"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_recycle_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectIdeaApiImpl) CreateGroup(ctx context.Context, req *project_idea_api.CreateGroupRequest) (*project_idea_api.CreateGroupResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.CreateGroupResponse{
			Code:   project_idea_api.CreateGroupResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.CreateGroupResponse{
			Code:   project_idea_api.CreateGroupResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.CreateGroupResponse{
			Code:   project_idea_api.CreateGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_idea_api.CreateGroupResponse{
			Code:   project_idea_api.CreateGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_idea_api.CreateGroupResponse{
			Code:   project_idea_api.CreateGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	ideaGroupId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = idea_dao.IdeaGroupDao.Insert(sessCtx, &idea_dao.IdeaGroupDbItem{
			IdeaGroupId:  ideaGroupId,
			Name:         req.Name,
			ProjectId:    req.ProjectId,
			Weight:       req.Weight,
			IdeaCount:    0,
			CreateUserId: sessionItem.UserId,
			UpdateUserId: sessionItem.UserId,
			CreateTime:   nowTime,
			UpdateTime:   nowTime,
		})
		if err != nil {
			return nil, err
		}
		return &project_idea_api.CreateGroupResponse{
			Code: project_idea_api.CreateGroupResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.CreateGroupNotice{
		ProjectId: req.ProjectId,
	})
	return ret.(*project_idea_api.CreateGroupResponse), nil
}

func (apiImpl *ProjectIdeaApiImpl) UpdateGroup(ctx context.Context, req *project_idea_api.UpdateGroupRequest) (*project_idea_api.UpdateGroupResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.UpdateGroupResponse{
			Code:   project_idea_api.UpdateGroupResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.UpdateGroupResponse{
			Code:   project_idea_api.UpdateGroupResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.UpdateGroupResponse{
			Code:   project_idea_api.UpdateGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_idea_api.UpdateGroupResponse{
			Code:   project_idea_api.UpdateGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_idea_api.UpdateGroupResponse{
			Code:   project_idea_api.UpdateGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	exist, err := idea_dao.IdeaGroupDao.Exist(ctx, req.ProjectId, req.IdeaGroupId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_idea_api.UpdateGroupResponse{
			Code:   project_idea_api.UpdateGroupResponse_CODE_NO_IDEA_GROUP,
			ErrMsg: "知识点分组不存在",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = idea_dao.IdeaGroupDao.UpdateNameAndWeight(sessCtx, req.ProjectId, req.IdeaGroupId, req.Name, req.Weight, sessionItem.UserId, nowTime)
		if err != nil {
			return nil, err
		}
		return &project_idea_api.UpdateGroupResponse{
			Code: project_idea_api.UpdateGroupResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.UpdateGroupNotice{
		ProjectId:   req.ProjectId,
		IdeaGroupId: req.IdeaGroupId,
	})
	return ret.(*project_idea_api.UpdateGroupResponse), nil
}

func (apiImpl *ProjectIdeaApiImpl) ListGroup(ctx context.Context, req *project_idea_api.ListGroupRequest) (*project_idea_api.ListGroupResponse, error) {
	emptyList := []*project_idea_api.IdeaGroup{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.ListGroupResponse{
			Code:      project_idea_api.ListGroupResponse_CODE_WRONG_SESSION,
			ErrMsg:    "会话不存在",
			GroupList: emptyList,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.ListGroupResponse{
			Code:      project_idea_api.ListGroupResponse_CODE_NO_PROJECT,
			ErrMsg:    "项目不存在",
			GroupList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.ListGroupResponse{
			Code:      project_idea_api.ListGroupResponse_CODE_NO_PERMISSION,
			ErrMsg:    "没有权限",
			GroupList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	ideaGroupItemList, err := idea_dao.IdeaGroupDao.List(ctx, req.ProjectId)
	if err != nil {
		return nil, err
	}
	//获取用户信息
	userIdList := []string{}
	for _, ideaGroupItem := range ideaGroupItemList {
		userIdList = append(userIdList, ideaGroupItem.CreateUserId)
		userIdList = append(userIdList, ideaGroupItem.UpdateUserId)
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}

	//生成结果
	groupList := []*project_idea_api.IdeaGroup{}
	for _, ideaGroupItem := range ideaGroupItemList {
		group := ideaGroupItem.ToIdeaGroup()
		createUser, ok := userItemMap[group.CreateUserId]
		if ok {
			group.CreateDisplayName = createUser.BasicInfo.DisplayName
			group.CreateLogoUri = createUser.BasicInfo.LogoUri
		}
		updateUser, ok := userItemMap[group.UpdateUserId]
		if ok {
			group.UpdateDisplayName = updateUser.BasicInfo.DisplayName
			group.UpdateLogoUri = updateUser.BasicInfo.LogoUri
		}
		groupList = append(groupList, group)
	}

	return &project_idea_api.ListGroupResponse{
		Code:      project_idea_api.ListGroupResponse_CODE_OK,
		GroupList: groupList,
	}, nil
}

func (apiImpl *ProjectIdeaApiImpl) GetGroup(ctx context.Context, req *project_idea_api.GetGroupRequest) (*project_idea_api.GetGroupResponse, error) {
	emptyGroup := &project_idea_api.IdeaGroup{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.GetGroupResponse{
			Code:   project_idea_api.GetGroupResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
			Group:  emptyGroup,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.GetGroupResponse{
			Code:   project_idea_api.GetGroupResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
			Group:  emptyGroup,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.GetGroupResponse{
			Code:   project_idea_api.GetGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
			Group:  emptyGroup,
		}, nil
	} else if err != nil {
		return nil, err
	}

	groupItem, err := idea_dao.IdeaGroupDao.Get(ctx, req.ProjectId, req.IdeaGroupId)
	if err != nil {
		return &project_idea_api.GetGroupResponse{
			Code:   project_idea_api.GetGroupResponse_CODE_NO_IDEA_GROUP,
			ErrMsg: "知识点分组不存在",
			Group:  emptyGroup,
		}, nil
	}

	//获取用户信息
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, []string{groupItem.CreateUserId, groupItem.UpdateUserId})
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}

	group := groupItem.ToIdeaGroup()
	createUser, ok := userItemMap[group.CreateUserId]
	if ok {
		group.CreateDisplayName = createUser.BasicInfo.DisplayName
		group.CreateLogoUri = createUser.BasicInfo.LogoUri
	}
	updateUser, ok := userItemMap[group.UpdateUserId]
	if ok {
		group.UpdateDisplayName = updateUser.BasicInfo.DisplayName
		group.UpdateLogoUri = updateUser.BasicInfo.LogoUri
	}

	return &project_idea_api.GetGroupResponse{
		Code:  project_idea_api.GetGroupResponse_CODE_OK,
		Group: group,
	}, nil
}

func (apiImpl *ProjectIdeaApiImpl) RemoveGroup(ctx context.Context, req *project_idea_api.RemoveGroupRequest) (*project_idea_api.RemoveGroupResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.RemoveGroupResponse{
			Code:   project_idea_api.RemoveGroupResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.RemoveGroupResponse{
			Code:   project_idea_api.RemoveGroupResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.RemoveGroupResponse{
			Code:   project_idea_api.RemoveGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_idea_api.RemoveGroupResponse{
			Code:   project_idea_api.RemoveGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_idea_api.RemoveGroupResponse{
			Code:   project_idea_api.RemoveGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	ideaGroupItem, err := idea_dao.IdeaGroupDao.Get(ctx, req.ProjectId, req.IdeaGroupId)
	if err != nil { //分组不存在
		return &project_idea_api.RemoveGroupResponse{
			Code: project_idea_api.RemoveGroupResponse_CODE_OK,
		}, nil
	}
	if ideaGroupItem.IdeaCount > 0 {
		return &project_idea_api.RemoveGroupResponse{
			Code:   project_idea_api.RemoveGroupResponse_CODE_HAS_IDEA,
			ErrMsg: "包含未删除知识点",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = idea_dao.IdeaGroupDao.Remove(sessCtx, req.ProjectId, req.IdeaGroupId)
		if err != nil {
			return nil, err
		}
		return &project_idea_api.RemoveGroupResponse{
			Code: project_idea_api.RemoveGroupResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.RemoveGroupNotice{
		ProjectId:   req.ProjectId,
		IdeaGroupId: req.IdeaGroupId,
	})
	return ret.(*project_idea_api.RemoveGroupResponse), nil
}

func (apiImpl *ProjectIdeaApiImpl) ClearGroup(ctx context.Context, req *project_idea_api.ClearGroupRequest) (*project_idea_api.ClearGroupResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.ClearGroupResponse{
			Code:   project_idea_api.ClearGroupResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.ClearGroupResponse{
			Code:   project_idea_api.ClearGroupResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.ClearGroupResponse{
			Code:   project_idea_api.ClearGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_idea_api.ClearGroupResponse{
			Code:   project_idea_api.ClearGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_idea_api.ClearGroupResponse{
			Code:   project_idea_api.ClearGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	ideaGroupItem, err := idea_dao.IdeaGroupDao.Get(ctx, req.ProjectId, req.IdeaGroupId)
	if err != nil { //分组不存在
		return &project_idea_api.ClearGroupResponse{
			Code: project_idea_api.ClearGroupResponse_CODE_OK,
		}, nil
	}

	ideaItemList, err := idea_dao.IdeaDao.List(ctx, req.ProjectId, &project_idea_api.ListIdeaParam{
		FilterByGroupId: true,
		GroupId:         req.IdeaGroupId,
	}, project_idea_api.IDEA_SORT_TYPE_IDEA_SORT_UPDATE_TIME, 0, math.MaxInt64)
	if err != nil {
		return nil, err
	}
	tmpKeywordMap := map[string]bool{}
	allKeywordList := []string{}
	for _, ideaItem := range ideaItemList {
		for _, kw := range ideaItem.BasicInfo.KeywordList {
			tmpKeywordMap[kw] = true
		}
	}
	for kw := range tmpKeywordMap {
		allKeywordList = append(allKeywordList, kw)
	}

	removeKeywordList := []string{}
	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		for _, ideaItem := range ideaItemList {
			err = idea_dao.IdeaDao.Remove(sessCtx, req.ProjectId, ideaItem.IdeaId)
			if err != nil {
				return nil, err
			}
			err = idea_dao.IdeaRecycleDao.Insert(sessCtx, ideaItem)
			if err != nil {
				return nil, err
			}
			err = project_dao.RecycleDao.Insert(sessCtx, &project_dao.RecycleItemInfoDbItem{
				RecycleItemId:   ideaItem.IdeaId,
				ProjectId:       req.ProjectId,
				RecycleItemType: uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_IDEA),
				RemoveUserId:    sessionItem.UserId,
				RemoveTime:      nowTime,
			})
			if err != nil {
				return nil, err
			}
		}
		//调整分组计数
		count, err := idea_dao.IdeaDao.Count(sessCtx, req.ProjectId, &project_idea_api.ListIdeaParam{
			FilterByGroupId: true,
			GroupId:         req.IdeaGroupId,
		})
		if err != nil {
			return nil, err
		}
		err = idea_dao.IdeaGroupDao.UpdateIdeaCount(sessCtx, req.ProjectId, req.IdeaGroupId, count)
		if err != nil {
			return nil, err
		}
		//计算移除的keyword
		existKeywordList, err := idea_dao.IdeaDao.ListExistKeyword(sessCtx, req.ProjectId, allKeywordList)
		if err != nil {
			return nil, err
		}
		for _, keyword := range allKeywordList {
			exist := false
			for _, cmpKeyword := range existKeywordList {
				if keyword == cmpKeyword {
					exist = true
					break
				}
			}
			if !exist {
				removeKeywordList = append(removeKeywordList, keyword)
			}
		}
		return &project_idea_api.ClearGroupResponse{
			Code: project_idea_api.ClearGroupResponse_CODE_OK,
		}, nil
	})

	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addClearGroupEvent(sessionItem, projectItem, ideaGroupItem, nowTime)
	//发送通知
	if len(removeKeywordList) != 0 {
		//发送keyword变化通知
		go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.KeywordChangeNotice{
			ProjectId:         req.ProjectId,
			AddKeywordList:    []string{},
			RemoveKeywordList: removeKeywordList,
		})
	}
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.UpdateGroupNotice{
		ProjectId:   req.ProjectId,
		IdeaGroupId: req.IdeaGroupId,
	})
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.ClearGroupNotice{
		ProjectId:   req.ProjectId,
		IdeaGroupId: req.IdeaGroupId,
	})
	return ret.(*project_idea_api.ClearGroupResponse), nil
}
